<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>使用自定义requestIdleWork的图片加载示例</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#3B82F6',
            secondary: '#64748B',
          },
          fontFamily: {
            sans: ['Inter', 'system-ui', 'sans-serif'],
          },
        },
      }
    }
  </script>
  <style type="text/tailwindcss">
    @layer utilities {
      .image-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
        gap: 1rem;
      }
      .image-card {
        @apply bg-white rounded-lg overflow-hidden shadow-md transition-all duration-300 hover:shadow-lg;
      }
      .image-placeholder {
        @apply bg-gray-100 flex items-center justify-center;
        aspect-ratio: 4/3;
      }
      .progress-container {
        @apply fixed bottom-4 left-1/2 transform -translate-x-1/2 bg-white px-4 py-2 rounded-full shadow-lg flex items-center gap-2 z-10;
      }
    }
  </style>
</head>
<body class="bg-gray-50 min-h-screen p-4 md:p-6">
  <header class="mb-6">
    <h1 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-gray-800">使用自定义requestIdleWork的图片加载</h1>
    <p class="text-gray-600">使用封装的空闲时间处理函数优化图片加载，不阻塞主线程</p>
  </header>

  <div id="progress" class="progress-container hidden">
    <i class="fa fa-spinner fa-spin text-primary"></i>
    <span id="progressText">加载中: 0/50</span>
    <div class="w-24 bg-gray-200 rounded-full h-2 overflow-hidden">
      <div id="progressBar" class="bg-primary h-full w-0 transition-all duration-300"></div>
    </div>
  </div>

  <div id="imageContainer" class="image-grid"></div>

  <script>
    // 封装的requestIdleWork函数
    function requestIdleWork(workFn, timeout = 100) {
      if (typeof requestIdleCallback === 'function') {
        requestIdleCallback(nonEssentialWork, { timeout })
      } else {
        // 降级为setTimeout
        setTimeout(workFn, timeout)
      }
      
      function nonEssentialWork(deadline) {
        // 如果帧内有富余的时间，或者超时
        if ((deadline?.timeRemaining && deadline.timeRemaining() > 0) || (timeout && deadline?.didTimeout)) {
          workFn()
        } else {
          requestIdleCallback(nonEssentialWork, { timeout })
        }
      }
    }

    // 生成50个随机图片URL（使用picsum.photos服务）
    const generateImageUrls = (count) => {
      return Array.from({ length: count }, (_, i) => {
        // 生成随机宽度和高度，保持4:3比例
        // const width = 400 + Math.floor(Math.random() * 200);
        // const height = Math.floor(width * 0.75);
        const width = 300;
        const height = 200;
        // 使用不同的seed确保图片不同
        return `https://picsum.photos/seed/${i + 1000}/${width}/${height}`;
      });
    };

    // 配置
    const config = {
      totalImages: 50,
      batchSize: 3, // 每次空闲时间加载的图片数量
      idleTimeout: 1000, // 空闲处理超时时间
    };

    // 初始化
    const images = generateImageUrls(config.totalImages);
    const imageContainer = document.getElementById('imageContainer');
    const progressElement = document.getElementById('progress');
    const progressText = document.getElementById('progressText');
    const progressBar = document.getElementById('progressBar');
    let loadedCount = 0;

    // 更新进度显示
    const updateProgress = () => {
      const percentage = (loadedCount / config.totalImages) * 50;
      progressText.textContent = `加载中: ${loadedCount}/${config.totalImages}`;
      progressBar.style.width = `${percentage}%`;
      
      // 显示或隐藏进度条
      if (loadedCount < config.totalImages) {
        progressElement.classList.remove('hidden');
      } else {
        progressElement.classList.add('hidden');
      }
    };

    // 创建图片元素并添加到容器
    const createImageElement = (url) => {
      // 创建图片容器
      const card = document.createElement('div');
      card.className = 'image-card';
      
      // 创建加载占位符
      const placeholder = document.createElement('div');
      placeholder.className = 'image-placeholder';
      placeholder.innerHTML = '<i class="fa fa-image text-gray-300 text-2xl"></i>';
      card.appendChild(placeholder);
      
      // 创建图片元素
      const img = document.createElement('img');
      img.className = 'w-full h-full object-cover opacity-0 transition-opacity duration-500';
      img.alt = '随机图片';
      
      // 图片加载完成处理
      img.onload = () => {
        placeholder.remove();
        img.classList.remove('opacity-0');
        loadedCount++;
        updateProgress();
      };
      
      // 图片加载错误处理
      img.onerror = () => {
        placeholder.innerHTML = '<i class="fa fa-exclamation-triangle text-amber-500 text-2xl"></i>';
        loadedCount++;
        updateProgress();
      };
      
      card.appendChild(img);
      imageContainer.appendChild(card);
      
      // 触发图片加载
      img.src = url;
    };

    // 加载图片的函数，会在空闲时间被调用
    const loadImages = () => {
      // 每次处理一批图片
      let loadedInBatch = 0;
      while (images.length > 0 && loadedInBatch < config.batchSize && document.visibilityState === 'visible') {
        const imageUrl = images.shift();
        createImageElement(imageUrl);
        loadedInBatch++;
      }
      
      // 如果还有图片没加载完，继续请求下一次空闲时间
      if (images.length > 0) {
        requestIdleWork(loadImages, config.idleTimeout);
      }
    };

    // 开始加载图片
    updateProgress();
    requestIdleWork(loadImages, config.idleTimeout);

    // 当页面从后台回到前台时，继续加载
    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'visible' && images.length > 0) {
        requestIdleWork(loadImages, config.idleTimeout);
      }
    });
  </script>
</body>
</html>
